package org.sqlproc.engine.impl.type;

import java.lang.reflect.Method;
import java.util.Collection;

import org.hibernate.Query;
import org.hibernate.type.Type;
import org.sqlproc.engine.SqlRuntimeException;
import org.sqlproc.engine.impl.BeanUtils;

/**
 * The common ancestor of all generic SQL META Types. These internal types are based on standard processing of the
 * input/output values.
 * 
 * @author <a href="mailto:Vladimir.Hudec@gmail.com">Vladimir Hudec</a>
 */
public abstract class SqlGenericType extends SqlMetaType {

    /**
     * The Hibernate type. A standard way to assign the type of parameter/scalar binding to the Hibernate Query.
     */
    public abstract Type getHibernateType();

    /**
     * The list of Java class type;
     */
    public abstract Class<?>[] getClassTypes();

    /**
     * The list of String representation of the internal types, which means special processing of the input/output
     * value.
     */
    public abstract String[] getMetaTypes();

    /**
     * {@inheritDoc}
     */
    @Override
    public void setResult(Object resultInstance, String attributeName, Object resultValue, boolean ingoreError)
            throws SqlRuntimeException {
        if (logger.isTraceEnabled()) {
            logger.trace(">>> setResult " + getMetaTypes()[0] + ": resultInstance=" + resultInstance
                    + ", attributeName=" + attributeName + ", resultValue=" + resultValue);
        }
        Method m = BeanUtils.getSetter(resultInstance, attributeName, getClassTypes());
        if (m != null)
            BeanUtils.simpleInvokeMethod(m, resultInstance, resultValue);
        else if (ingoreError) {
            logger.error("There's no getter for " + attributeName + " in " + resultInstance + ", META type is "
                    + getMetaTypes()[0]);
        } else {
            throw new SqlRuntimeException("There's no setter for " + attributeName + " in " + resultInstance
                    + ", META type is " + getMetaTypes()[0]);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setParameter(Query query, String paramName, Object inputValue, Class<?> inputType, boolean ingoreError)
            throws SqlRuntimeException {
        if (logger.isTraceEnabled()) {
            logger.trace(">>> setParameter " + getMetaTypes()[0] + ": paramName=" + paramName + ", inputValue="
                    + inputValue + ", inputType=" + inputType);
        }
        if (inputValue == null) {
            query.setParameter(paramName, inputValue, getHibernateType());
        } else {
            if (inputValue instanceof Collection) {
                query.setParameterList(paramName, ((Collection) inputValue).toArray(), getHibernateType());
            } else {
                query.setParameter(paramName, inputValue, getHibernateType());
            }
        }
    }
}
